#include "CVM.h"

#include <string>

#include "COperationCodes.h"
#include "CCoreException.h"
#include "operations/CCommon.h"
#include "operations/CCalculations.h"
#include "operations/CFlow.h"

CVM::CVM(char* code, int size)
{
    this->code = code;
    this->codeSize = size;
}

void CVM::start()
{
    frames.push(new CFrame(code, codeSize, QHash<QString, char*>(), references));
    while(!frames.isEmpty())
    {
        while(frames.top()->pointer() < frames.top()->codeSize()) execute();
        delete frames.pop();
    }
}

void CVM::execute()
{
    int& pointer = frames.top()->pointer();
    COperationCodes opcd = (COperationCodes)frames.top()->code()[pointer++];
    switch(opcd)
    {
        case COperationCodes::PUSH:
        {
            push(*frames.top());
            break;
        }
        case COperationCodes::POP:
        {
            pop(*frames.top());
            break;
        }
        case COperationCodes::BIND:
        {
            bind(*frames.top());
            break;
        }
        case COperationCodes::GET_VAR:
        {
            getVar(*frames.top());
            break;
        }
        case COperationCodes::IF:
        {
            if_(*frames.top());
            break;
        }
        case COperationCodes::GO_TO:
        {
            goTo(*frames.top());
            break;
        }
        case COperationCodes::FUNC:
        {
            func(*frames.top());
            break;
        }
        case COperationCodes::CALL:
        {
            call(frames);
            break;
        }
        case COperationCodes::RET:
        {
            ret(frames);
            break;
        }
        case COperationCodes::END:
        {
            break;
        }
        case COperationCodes::OR:
        case COperationCodes::AND:
        {
            orAnd(*frames.top(), opcd);
            break;
        }
        case COperationCodes::NOT:
        {
            not_(*frames.top());
            break;
        }
        case COperationCodes::EQ:
        case COperationCodes::NEQ:
        case COperationCodes::GTE:
        case COperationCodes::GT:
        case COperationCodes::LTE:
        case COperationCodes::LT:
        {
            egNeqGteGtLteLt(*frames.top(), opcd);
            break;
        }
        case COperationCodes::ADD:
        case COperationCodes::SUB:
        case COperationCodes::MUL:
        case COperationCodes::DIV:
        {
            addSubMulDiv(*frames.top(), opcd);
            break;
        }
        default:
            throw CCoreException(CCoreException::VM_EXCEPTION_WRONG_OPERATION);
    }
}
